/*
author:yiliangwu880
you can get more refer from https://gitee.com/yiliangwu880/svr_util.git
brief: 延时处理逻辑， DelayOptMgr 的递归版本,效率会低点。推荐使用 DelayOptMgr，遇到递归需求，改为下个定时器执行吧。
目的:
例子：
	class MyOptMgr: public DelayOptMgrRecur<MyTarget, uint64>
	{
	public:
		virtual MyTarget *OnFindTarget(uint64 target_id)				//1 实现查找内存目标,查找失败返回nullptr	
		{
			...
		}

		virtual void OnMissTarget(uint64 target_id)						//2 实现，请求读档。  (内存没有对象时会调用）
		{
			...
		}
	};

	MyOptMgr mgr;

	mgr.OnLoadOk(ObjId target_id, Obj &target);//读库成功后调用
	mgr.OnLoadFail(ObjId target_id);	//读库失败后

	                                                                    //5 加入操作请求
	auto opt = [](TargetType &target){};                                //注意，回调函数可能异步调用。引用的对象别野         
	mgr.AddOpt(target_id, opt);

一次请求获取多个目标例子：
	MyOptMgr mgr;
	auto opt = [](vector<TargetType*> targetList){};                                //注意，回调函数可能异步调用。引用的对象别野    
	mgr.AddOptList(idList, opt);

*/

#pragma once
#include "../typedef.h"
#include <stdio.h>
#include <vector>
#include <map>
#include <utility>
#include <list>
#include <functional>

#ifdef L_DEBUG
#else
#define L_DEBUG(x, ...)  printf(x, ##__VA_ARGS__); //根据自己项目自定义日志
#endif
#ifdef L_ERROR
#else
#define L_ERROR(x, ...)  printf(x, ##__VA_ARGS__); //根据自己项目自定义日志
#endif

//@Obj			 被操作的对象
//@ObjId		 对象的 id
//@MAX_OPT_NUM   每个对象最大缓存函数对象数
template<class Obj, class ObjId=uint64, const uint32 MAX_OPT_NUM = 3>
class  DelayOptMgrRecur
{
public:
	using OptFun = std::function<void(Obj &)>;
	using OptFunFail = std::function<void(ObjId id)>;
	using OptListFun = std::function<void(std::vector<Obj*> targetList)>;
	using OptListFunFail = std::function<void()>;
private:
	struct Fun 
	{
		OptFun fun=nullptr;
		OptFunFail funFail = nullptr;
	};
	typedef std::vector<Fun> VecDelayOpt;
	struct TargetOpt
	{
		VecDelayOpt vec_opt;
		bool is_opting = false;				                            //true表示进入BaseDelayOptMgr::OptTarget运行中
	};
	typedef std::map<ObjId, TargetOpt> Id2Vec;

	struct OptReq
	{
		uint32 okCnt = 0;
		uint32 failCnt = 0;
		OptListFun opt;
		OptListFunFail optFail;
		std::vector<ObjId> allList;
	};
	typedef std::list<OptReq> OptReqList; //记录请求列表的 请求进度. 不能用vector，因为删除元素时，迭代器会失效

	Id2Vec m_id_2_vec;		                                            //id 2 vec, vec ==opt list
	OptReqList m_opt_req_list;

public:
	//加一个操作.		(目标找到马上执行，不在就等调用  HandleTarget 再操作)
	//注意：你传一些指针，引用进去延后调用，就需要注意是否会野指针。
	//@optFail 获取Obj失败的情况调用
	void AddOpt(ObjId target_id, OptFun opt, OptFunFail optFail = nullptr);
	void OnLoadOk(ObjId target_id, Obj &target);
	void OnLoadFail(ObjId target_id);// 加载失败后调用， 删除目标缓存操作 

	//一次请求获取多个目标,低效不推荐用，无其他替代方法采用
	//@opt 成功获取所有目标后调用,不会有nullptr对象
	//@optFail 获取任意Obj失败的情况调用
	void AddOptList(std::vector<ObjId> target_id_list, OptListFun opt, OptListFunFail optFail = nullptr);
	 //for test use
	uint32 GetMaxNum() const {return MAX_OPT_NUM;}
	uint32 GetOptNum(ObjId target_id);
private:
    virtual Obj *OnFindTarget(ObjId target_id)=0;			//实现查找内存目标
	virtual void OnMissTarget(ObjId target_id) = 0;				    //实现，请求读档。  (内存没有对象时的第一个操作才请求才会调用）

	void RemoveOptReqList(OptReq &req);
	void OptTarget(ObjId target_id, Obj &target);//对目标操作缓存操作

public:

};


template<class Obj, class ObjId, const uint32 MAX_OPT_NUM>
void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::OptTarget(ObjId target_id, Obj &target)
{
	auto it = m_id_2_vec.find(target_id);
	if (it == m_id_2_vec.end())
	{
		return;
	}

	TargetOpt &target_opt = it->second;
	if (target_opt.is_opting)
	{
		return;//跑这里属于递归调用，退出不用处理。第一次调用进来的函数会处理
	}
	target_opt.is_opting = true;
	int cnt = 0;
	while (true)
	{
		//////////////测试错误代码，后期没错可以删掉//////////
		cnt++;
		if (cnt > 100)
		{
			L_ERROR("error,  endless loop?\n");
		}
		////////////////////////////////////////
		if (target_opt.vec_opt.empty())
		{
			break;
		}

		//复制一份,避免直接引用 m_id_2_vec 导致下面递归错误。 用局部变量 vec_opt 操作，确保不会被回调函数修改。
		VecDelayOpt vec_opt;
		vec_opt.swap(target_opt.vec_opt);

		for(Fun opt: vec_opt)
		{
			if (nullptr == opt.fun)
			{
				L_ERROR("error, why save null point?\n");
				continue;
			}
			opt.fun(target);//里面会可能继续调用AddOpt，给m_id_2_vec[id]加成员
		}

	}
	m_id_2_vec.erase(it);
}

template<class Obj, class ObjId, const uint32 MAX_OPT_NUM>
void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::AddOpt(ObjId target_id, OptFun opt, OptFunFail optFail )
{
	if (nullptr == opt || ObjId() == target_id)
	{
		L_ERROR("error para \n");
		return;
	}

	VecDelayOpt &vec_opt = m_id_2_vec[target_id].vec_opt;
	if (vec_opt.size() >= MAX_OPT_NUM)
	{
		//缓存操作太多了，操作不过来，看下应用代码是不是设计错误，还是	MAX_OPT_NUM 需要调大？
		vec_opt.clear();
		L_ERROR("error, req is too more, id=%ld\n", target_id);
		return;
	}

	vec_opt.push_back({ opt, optFail });

	if (Obj *pTarget = OnFindTarget(target_id))
	{
		OptTarget(target_id, *pTarget);
	}
	else
	{
		//req get target from db
		if (vec_opt.size() == 1) //第一个操作才请求读库
		{
			OnMissTarget(target_id);
		}
	}
}

template <class Obj, class ObjId, uint32 MAX_OPT_NUM>
inline void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::OnLoadOk(ObjId target_id, Obj &target)
{
	OptTarget(target_id, target);
}

template <class Obj, class ObjId, uint32 MAX_OPT_NUM>
inline void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::OnLoadFail(ObjId target_id)
{
	typename Id2Vec::iterator it = m_id_2_vec.find(target_id);
	if (it == m_id_2_vec.end())
	{
		return;
	}
	VecDelayOpt& vec_opt = it->second.vec_opt;
	for (Fun &v : vec_opt)
	{
		if (v.funFail != nullptr)
		{
			v.funFail(target_id);
		}
	}
	m_id_2_vec.erase(it);
}

template<class Obj, class ObjId, const uint32 MAX_OPT_NUM>
void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::AddOptList(std::vector<ObjId> target_id_list, OptListFun opt, OptListFunFail optFail)
{
	if (nullptr == opt)
	{
		L_ERROR("error para \n");
		return;
	}

	OptReq &req = m_opt_req_list.emplace_back();
	req.allList = target_id_list;
	req.opt = opt;
	req.optFail = optFail;
	if (m_opt_req_list.size() >= MAX_OPT_NUM)
	{
		//缓存操作太多了，操作不过来，看下应用代码是不是设计错误，还是	MAX_OPT_NUM 需要调大？
		m_opt_req_list.clear();
		L_ERROR("error, AddOptList is too more\n");
		return;
	}
	
	auto oneOpt = [&req, this](Obj& target){
		req.okCnt++;
		if (req.okCnt + req.failCnt != req.allList.size())
		{
			return;
		}

		if (req.failCnt > 0)
		{
			req.optFail();
			RemoveOptReqList(req);
			return;
		}

		std::vector<Obj*> targetList;
		for (auto id: req.allList)
		{
			Obj* pTarget = OnFindTarget(id);
			if (nullptr == pTarget)
			{
				L_ERROR("error, target not found");
				return;
			}
			targetList.push_back(pTarget);
		}
		req.opt(targetList);
		RemoveOptReqList(req);
	};

	auto oneOptFail = [&req, this, optFail](ObjId id){
		req.failCnt++;
		if (req.okCnt + req.failCnt != req.allList.size())
		{
			return;
		}

		req.optFail();
		RemoveOptReqList(req);
	};

	for (auto id: target_id_list)
	{
		AddOpt(id, oneOpt, oneOptFail);
	}
}


template<class Obj, class ObjId, const uint32 MAX_OPT_NUM>
uint32 DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::GetOptNum(ObjId target_id)
{
	typename Id2Vec::iterator it = m_id_2_vec.find(target_id);
	if (it == m_id_2_vec.end())
	{
		return 0;
	}
	VecDelayOpt &vec_opt = it->second.vec_opt;
	return vec_opt.size();
}

template <class Obj, class ObjId, uint32 MAX_OPT_NUM>
inline void DelayOptMgrRecur<Obj, ObjId, MAX_OPT_NUM>::RemoveOptReqList(OptReq &req)
{
	for (typename OptReqList::iterator iter = m_opt_req_list.begin(); iter != m_opt_req_list.end(); ++iter)
	{
		if (&req == &(*iter))
		{
			m_opt_req_list.erase(iter);
			return;
		}
	}
	L_ERROR("error, RemoveOptReqList not found\n");
}
